package graphs;

import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.Point;
import java.util.ArrayList;
import java.util.ListIterator;
import javax.swing.text.html.HTMLDocument.Iterator;
import tester.Example;
import tester.Tester;
import tester.cobertura.Instrument;
import lists.MyArrayList;
import lists.UnaryFunction;
import abstractions.Abstractions;

/**
 * <h1> Title : Vertex  </h1>
 * <p> Description : Generalization of a vertex. It is an Object (i.e A
 * City). Cloneable. </p>
 * 
 * @author Adam Blackwell & Ryan Cassidy
 * @since February 22nd 2009
 * @version 1.2
 */
@Instrument @Example public abstract class Vertex implements Cloneable {
  public MyArrayList<Link> neighbors; // All links to connected nodes.
  private String           name;     // The name of the node.
  private Point            loc;      // Location
  
  /**
   * <p> Constructor : </p> 
   * 
   * @param neighbors
   */
  public Vertex(String name, MyArrayList<Link> neighbors, Point loc) {
    this.name = name;
    this.neighbors = neighbors;
    this.loc = loc;
  }
  
  /**
   * <p> Default Constructor : </p> 
   */
  public Vertex(String name) {
    this.name = name;
    this.neighbors = new MyArrayList<Link>();
    this.loc = new Point();
  }
  
  public Vertex() {
    this.name = "";
    this.neighbors = new MyArrayList<Link>();
    this.loc = new Point();
  }
  
  //=================================================================
  // Construction Methods:
  //=================================================================
  
  /**
   * <p> AddNeighbor : Adds the given vertex, with the given weight, 
   * to the {neighbors} field. </p> 
   * 
   * @param n
   */
  public void addNeighbor(int w, Vertex n) {
    this.neighbors.add(new Link(w, n));
  }
  
  /**
   * <p> RemoveNeighbor : Finds the neighbor(s) identical to the one
   * passed in, and removes it from the {MyArrayList} {neighbors}.
   * 
   * @param n
   */
  public void removeNeighbor(final Vertex n) {
    this.neighbors.filter(new UnaryFunction<Boolean, Link>() {
      public Boolean f(Link l) {
        return !(l.getDestinationVertex().equals(n));
      }
    });
  }
  
  //=================================================================
  // Predicate Methods:
  //=================================================================
  
  /**
   * <p> HasNeighbor : Returns true if a {Vertex} identical to the one passed in
   * is contained in the {MyArrayList} {neighbors}, and returns
   * false otherwise. </p> 
   * 
   * @param v
   * @return boolean Representing whether the neighbor exists
   */
  public boolean hasNeighbor(final Vertex v) {
    return this.neighbors.ormap(new UnaryFunction<Boolean, Link>() {
      public Boolean f(Link il) {
        return il.getDestinationVertex().equals(v);
      }
    });
  }
  
  /**
   * <p> WeightToNeighbor : Searches through the {MyArrayList} {neighbors}
   * to find the weight specified in the {Link}. </p> 
   * 
   * @param v
   * @return the weight listed between this and that {Vertex}
   */
  public int weightToNeightbor(final Vertex v) {
    return this.neighbors.filter(new UnaryFunction<Boolean, Link>() {
      public Boolean f(Link l) {
        // Compares the names to check for desired Vertex.
        if (l.getDestinationVertex().getName().equals(v.getName())) {
          return true;
        } else {
          return false;
        }
      }
      //TODO: Ryan : The get method will throw, I think...
    }).get(0).getWeight();
  }
  

  /**
   * <p> DistanceTo : Calculates the distance between the two {Points} </p> 
   * 
   * @param destinationVertex
   * @return the distance to the vertex
   */
  public double distanceTo(Vertex destinationVertex) {
    // Uses the Point2D distance function.
    return this.loc.distance(destinationVertex.loc);
  }
  
  /**
   * <p> ToString : Creates the string representation of the Vertex. </p> 
   * 
   * @return the String representation of the {Vertex}
   */
  public String toString() {
    return this.name;
  }
  
  //=================================================================
  // Draw Methods:
  //=================================================================
  
//  /*
//   * (non-Javadoc)
//   * @see graphs.IPlottable#draw(java.awt.Canvas)
//   */
//  public abstract void draw(Graphics g);
//  
//  /**
//   * <p> DrawLinks : This function, when completed, will
//   * draw the links in the MyArrayList of the given node. </p> 
//   * 
//   * @param g
//   */
//  public abstract void drawLinks(Graphics g);
  
  //=================================================================
  // Getter & Setter Methods:
  //=================================================================
  

  /**
   * <p> GetInfo : Compiles a string for the graph to put next to the node.</p>
   * 
   * @return Info
   */
  public String getInfo() {
    return "";
  }
  
  /**
   * <p> GetName : Gets the name of the node. </p> 
   * 
   * @return The Vertex's name.
   */
  public String getName() {
    return name;
  }
  
  /**
   * <p> SetName : Changes the name of the node to the given string. </p> 
   * 
   * @param name
   */
  public void setName(String name) {
    this.name = name;
  }
  
  /**
   * <p> GetLoc : Gets the location value, a Point. </p> 
   * 
   * @return the loc
   */
  public Point getLoc() {
    if (this.loc.equals(new Point(0,0))){
      throw new RuntimeException("You did something very wrong");
    } else {
      return this.loc;
    }
  }
  
  //=================================================================
  // Test Methods:
  //=================================================================
  
  public void init(){
    // Create Vertices...
  }
  
  public void testRemoveNeighbor(Tester t) {
    t.checkExpect(true);
    t.checkExpect(true);
    t.checkExpect(true);
    t.checkExpect(true);
  }

  public void testHasNeighbor(Tester t) {
    t.checkExpect(true);
    t.checkExpect(true);
    t.checkExpect(true);
    t.checkExpect(true);
  }
  
  public void testWeightToNeighbor(Tester t) {
    t.checkExpect(true);
    t.checkExpect(true);
    t.checkExpect(true);
    t.checkExpect(true);
  }
  
  public void testToString(Tester t) {
    t.checkExpect(true);
    t.checkExpect(true);
    t.checkExpect(true);
    t.checkExpect(true);
  }

  public void testDraw(Tester t) {
    // How?...
    t.checkExpect(true);
    t.checkExpect(true);
    t.checkExpect(true);
    t.checkExpect(true);
  }

  public void testDrawLinks(Tester t) {
    t.checkExpect(true);
    t.checkExpect(true);
    t.checkExpect(true);
    t.checkExpect(true);
  }

  public void testAddNeighbor(Tester t) {
    t.checkExpect(true);
    t.checkExpect(true);
    t.checkExpect(true);
    t.checkExpect(true);
  }

  public void setLinkVisited(String vertex) {
    // TODO Auto-generated method stub
    java.util.Iterator<Link> it = this.neighbors.iterator();
    while (it.hasNext()) {
      Link l = it.next();
      if (l.getDestinationVertex().getName().equals(vertex)){
        l.setVisited(true);
      }
    }
  }
}
